# -*- encoding: utf-8 -*-
require 'write_xlsx/package/xml_writer_simple'
require 'write_xlsx/utility'
require 'write_xlsx/chart/caption'

module Writexlsx
  class Chart
    class Axis < Caption
      include Writexlsx::Utility

      attr_accessor :defaults
      attr_accessor :min, :max, :num_format, :position, :major_tick_mark
      attr_reader :minor_unit, :major_unit, :minor_unit_type, :major_unit_type
      attr_reader :display_units_visible, :display_units
      attr_reader :log_base, :crossing, :position_axis, :label_position, :visible
      attr_reader :num_format_linked, :num_font, :layout, :interval_unit
      attr_reader :major_gridlines, :minor_gridlines, :reverse
      attr_reader :line, :fill, :text_axis
      #
      # Convert user defined axis values into axis instance.
      #
      def merge_with_hash(params) # :nodoc:
        super
        args      = (defaults || {}).merge(params)

        [
          :reverse, :min, :max, :minor_unit, :major_unit, :minor_unit_type,
          :major_unit_type, :log_base, :crossing, :position_axis,
          :label_position, :num_format, :num_format_linked, :interval_unit,
          :major_tick_mark, :line, :fill
        ].each { |val| instance_variable_set("@#{val}", args[val]) }
        @visible           = args[:visible] || 1

        set_major_minor_gridlines(args)
        set_display_units(args)
        set_display_units_visible(args)
        set_position(args)
        set_position_axis
        set_font_properties(args)
        set_axis_name_layout(args)
        set_axis_line(args)
        set_axis_fill(args)
        if ptrue?(args[:text_axis])
          @chart.date_category = false
          @text_axis = true
        end
      end

      #
      # Write the <c:numberFormat> element. Note: It is assumed that if a user
      # defined number format is supplied (i.e., non-default) then the sourceLinked
      # attribute is 0. The user can override this if required.
      #

      def write_number_format(writer) # :nodoc:
        writer.empty_tag('c:numFmt', num_fmt_attributes)
      end

      #
      # Write the <c:numFmt> element. Special case handler for category axes which
      # don't always have a number format.
      #
      def write_cat_number_format(writer, cat_has_num_fmt)
        return unless user_defined_num_fmt_set? || cat_has_num_fmt

        writer.empty_tag('c:numFmt', num_fmt_attributes)
      end

      private

      def user_defined_num_fmt_set?
        @defaults && @num_format != @defaults[:num_format]
      end

      def source_linked
        value = 1
        value = 0 if user_defined_num_fmt_set?
        value = 1 if @num_format_linked

        value
      end

      def num_fmt_attributes
        [
         ['formatCode',   @num_format],
         ['sourceLinked', source_linked]
        ]
      end

      def set_major_minor_gridlines(args)
        # Map major/minor_gridlines properties.
        [:major_gridlines, :minor_gridlines].each do |lines|
          if args[lines] && ptrue?(args[lines][:visible])
            instance_variable_set("@#{lines}", Gridline.new(args[lines]))
          else
            instance_variable_set("@#{lines}", nil)
          end
        end
      end

      #
      #
      # Convert user defined display units to internal units.
      #
      def get_display_units(display_units)

        return unless ptrue?(display_units)

        types = {
          'hundreds'          => 'hundreds',
          'thousands'         => 'thousands',
          'ten_thousands'     => 'tenThousands',
          'hundred_thousands' => 'hundredThousands',
          'millions'          => 'millions',
          'ten_millions'      => 'tenMillions',
          'hundred_millions'  => 'hundredMillions',
          'billions'          => 'billions',
          'trillions'         => 'trillions'
        }

        if types[display_units]
          return types[display_units]
        else
          # warn "Unknown display_units type '$display_units'\n"
          return
        end
      end

      def set_display_units(args)
        @display_units = get_display_units(args[:display_units])
      end

      def set_display_units_visible(args)
        if args[:display_units_visible]
          @display_units_visible = args[:display_units_visible]
        else
          @display_units_visible = 1;
        end
      end

      def set_position(args)
        # Only use the first letter of bottom, top, left or right.
        @position = args[:position]
        @position = @position.downcase[0, 1] if @position
      end

      def set_position_axis
        # Set the position for a category axis on or between the tick marks.
        if @position_axis
          if @position_axis == 'on_tick'
            @position_axis = 'midCat'
          elsif @position_axis == 'between'
            # Doesn't neet to be modified.
          else
            # Otherwise use the default value.
            @position_axis = nil
          end
        end
      end

      def set_font_properties(args)
        @num_font  = @chart.convert_font_args(args[:num_font])
        @name_font = @chart.convert_font_args(args[:name_font])
      end

      def set_axis_name_layout(args)
        @layout    = @chart.layout_properties(args[:name_layout], 1)
      end

      def set_axis_line(args)
        @line = @chart.line_properties(args[:line])
      end

      def set_axis_fill(args)
        @fill = @chart.fill_properties(args[:fill])
      end
    end
  end
end
